#include <stdio.h>
#include "gy33streamparser.h"
#include <string.h>


typedef struct _GY33StreamParser{

    unsigned char   state;

    unsigned char   lastByte;
    unsigned char   code;

    unsigned char   payloadLength;
    unsigned char   payloadBytesReceived;
    unsigned char   payload[256];
    unsigned char   payloadSum;
    unsigned char   chksum;

    void (*handleDataValue)(unsigned char code, const unsigned char *value,
                            unsigned char numBytes, void *customData);
    void  *customData;

}GY33StreamParser;


#define PARSER_STATE_NULL           0x00  /* NULL state */
#define PARSER_STATE_SYNC           0x01  /* Waiting for SYNC byte */
#define PARSER_STATE_SYNC_CHECK     0x02  /* Waiting for second SYNC byte */
#define PARSER_STATE_PAYLOAD_LENGTH 0x03  /* Waiting for payload[] length */
#define PARSER_STATE_PAYLOAD        0x04  /* Waiting for next payload[] byte */
#define PARSER_STATE_CHKSUM         0x05  /* Waiting for chksum byte */
#define PARSER_STATE_CODE           0x06  /* Waiting for cmd*/


/* Other constants */
#define PARSER_SYNC_BYTE            0x5A  /* Syncronization byte */
#define PARSER_EXCODE_BYTE          0x55  /* EXtended CODE level byte */
#define PARSER_DATA_MAXLENGTH       8


void *GY33_initParser(void (*handleDataValueFunc)(
                          unsigned char code, const unsigned char *value,
                          unsigned char numBytes, void *customData),
                      void *customData)
{


    GY33StreamParser *parser = malloc(sizeof(GY33StreamParser));

    if(parser == NULL)
        return parser;

    memset(parser, 0, sizeof(*parser));

    /* Save parser type */
    parser->state = PARSER_STATE_SYNC;

    /* Save user-defined handler function and data pointer */
    parser->handleDataValue = handleDataValueFunc;
    parser->customData = customData;

    return parser;
}

void GY33_ParserDestory(void *handle)
{

    GY33StreamParser *parser = (GY33StreamParser *)handle;

    if(parser != NULL)
        free(parser);
}


static int parsePacketPayload(void *handle)
{
    GY33StreamParser *parser = (GY33StreamParser *)handle;
    unsigned char code = 0;
    unsigned char numBytes = 0;

    if(parser == NULL)
        return -1;

    /* Parse CODE */
    code = parser->code;
    numBytes = parser->payloadLength;

    /* Call the callback function to handle the DataRow value */
    if( parser->handleDataValue )
    {
        parser->handleDataValue(code, parser->payload, numBytes, parser->customData);
    }


    return 0;
}


int GY33_parseByte(void *handle, unsigned char byte)
{

    GY33StreamParser *parser = (GY33StreamParser *)handle;

    int returnValue = 0;

    if(parser == NULL)
        return -1;

    /* Pick handling according to current state... */
    switch( parser->state ) {

        /* Waiting for SyncByte */
        case( PARSER_STATE_SYNC ):
            if( byte == PARSER_SYNC_BYTE ) {
                parser->state = PARSER_STATE_SYNC_CHECK;
            }
            break;

        /* Waiting for second SyncByte */
        case( PARSER_STATE_SYNC_CHECK ):
            if( byte == PARSER_SYNC_BYTE ) {
                parser->state = PARSER_STATE_CODE;
            } else {
                parser->state = PARSER_STATE_SYNC;
            }
            break;


        case( PARSER_STATE_CODE ):
            parser->code = byte;
            if( byte == PARSER_CODE_IICADDRESS)
            {
                parser->payloadLength = 1;
                parser->payloadBytesReceived = 0;
                parser->payloadSum = PARSER_SYNC_BYTE+PARSER_SYNC_BYTE+parser->code;
                parser->state = PARSER_STATE_PAYLOAD;

            } else {
                parser->state = PARSER_STATE_PAYLOAD_LENGTH;
            }
            break;

        /* Waiting for Data[] length */
        case( PARSER_STATE_PAYLOAD_LENGTH ):
            parser->payloadLength = byte;
            if( parser->payloadLength > PARSER_DATA_MAXLENGTH ) {
                parser->state = PARSER_STATE_SYNC;
                returnValue = -3;
            }
            else
            {
                parser->payloadBytesReceived = 0;
                parser->payloadSum = PARSER_SYNC_BYTE+PARSER_SYNC_BYTE+parser->code+parser->payloadLength;
                parser->state = PARSER_STATE_PAYLOAD;
            }
            break;

        /* Waiting for Payload[] bytes */
        case( PARSER_STATE_PAYLOAD ):
            parser->payload[parser->payloadBytesReceived++] = byte;
            parser->payloadSum = (unsigned char)(parser->payloadSum + byte);
            if( parser->payloadBytesReceived >= parser->payloadLength ) {
                parser->state = PARSER_STATE_CHKSUM;
            }
            break;

        /* Waiting for CKSUM byte */
        case( PARSER_STATE_CHKSUM ):
            parser->chksum = byte;
            parser->state = PARSER_STATE_SYNC;
            if( parser->chksum != parser->payloadSum) {
                returnValue = -2;
            } else {
                returnValue = 1;
                parsePacketPayload(parser);
            }
            break;

        /* unrecognized state */
        default:
            parser->state = PARSER_STATE_SYNC;
            returnValue = -5;
            break;
    }

    /* Save current byte */
    parser->lastByte = byte;

    return( returnValue );
}







